<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>加密货币行情分析工具</title>
    <script src="https://cdn.tailwindcss.com"></script>
    <link href="https://cdn.jsdelivr.net/npm/font-awesome@4.7.0/css/font-awesome.min.css" rel="stylesheet">
    <script>
        tailwind.config = {
            theme: {
                extend: {
                    colors: {
                        primary: '#165DFF',
                        secondary: '#36CFC9',
                        positive: '#52C41A',
                        'positive-light': '#7CCC92',
                        negative: '#F5222D',
                        'negative-light': '#F8A8A8',
                        dark: '#1D1D1F',
                        'dark-light': '#2C2C2E'
                    },
                    fontFamily: {
                        sans: ['Inter', 'system-ui', 'sans-serif'],
                    },
                }
            }
        }
    </script>
    <style type="text/tailwindcss">
        @layer utilities {
            .content-auto {
                content-visibility: auto;
            }
            .card-hover {
                @apply transition-all duration-300 hover:shadow-lg hover:shadow-primary/20 hover:-translate-y-1;
            }
            .btn-primary {
                @apply bg-primary hover:bg-primary/90 text-white font-medium py-2 px-4 rounded transition-all duration-200;
            }
            .btn-outline {
                @apply border border-gray-600 hover:border-primary text-gray-300 hover:text-white py-2 px-4 rounded transition-all duration-200;
            }
        }
    </style>
</head>
<body class="bg-gray-900 text-gray-100 min-h-screen">
    <!-- 顶部导航 -->
    <header class="bg-dark-light border-b border-gray-800 sticky top-0 z-50">
        <div class="container mx-auto px-4 py-4 flex justify-between items-center">
            <div class="flex items-center space-x-2">
                <i class="fa fa-line-chart text-primary text-2xl"></i>
                <h1 class="text-xl font-bold">加密货币分析工具</h1>
            </div>
            <div class="text-sm text-gray-400">
                <span id="last-update">最后更新: 未更新</span>
            </div>
        </div>
    </header>

    <!-- 主要内容区 -->
    <main class="container mx-auto px-4 py-8">
        <!-- 控制面板 -->
        <div class="bg-dark-light rounded-lg p-6 mb-8 shadow-lg">
            <div class="flex flex-col md:flex-row justify-between items-start md:items-center gap-4">
                <div>
                    <h2 class="text-xl font-semibold mb-2">市场分析</h2>
                    <p class="text-gray-400 text-sm">基于技术指标的加密货币市场分析与预测</p>
                </div>
                
                <div class="flex flex-col sm:flex-row gap-3 w-full md:w-auto">
                    <div class="flex items-center gap-2 w-full sm:w-auto">
                        <label for="analysis-period" class="text-sm text-gray-400">分析周期:</label>
                        <select id="analysis-period" class="bg-gray-800 border border-gray-700 rounded px-3 py-2 text-sm focus:outline-none focus:ring-1 focus:ring-primary w-full sm:w-auto">
                            <option value="10m">10分钟</option>
                            <option value="30m">30分钟</option>
                            <option value="1h" selected>1小时</option>
                        </select>
                    </div>
                    
                    <button id="start-analysis" class="btn-primary flex items-center justify-center gap-2 w-full sm:w-auto">
                        <i class="fa fa-refresh"></i>
                        <span>开始分析</span>
                    </button>
                </div>
            </div>
            
            <div class="mt-4 pt-4 border-t border-gray-800">
                <div id="loading-indicator" class="hidden flex items-center gap-2 text-gray-400">
                    <i class="fa fa-circle-o-notch fa-spin"></i>
                    <span>正在分析市场数据，请稍候...</span>
                </div>
                <div id="analysis-status" class="text-sm text-gray-400 hidden"></div>
            </div>
        </div>
        
        <!-- 分析结果展示区 -->
        <div class="grid grid-cols-1 md:grid-cols-2 gap-6" id="analysis-results">
            <!-- 分析结果卡片将在这里动态生成 -->
            <div class="flex items-center justify-center h-64 text-gray-500">
                <div class="text-center">
                    <i class="fa fa-bar-chart text-4xl mb-3"></i>
                    <p>点击"开始分析"按钮获取市场数据</p>
                </div>
            </div>
        </div>
    </main>

    <!-- 页脚 -->
    <footer class="bg-dark-light border-t border-gray-800 mt-12 py-6">
        <div class="container mx-auto px-4 text-center text-gray-500 text-sm">
            <p>加密货币分析工具 &copy; 2023 | 数据仅供参考，不构成投资建议</p>
        </div>
    </footer>

    <script>
        // 保留原有的JavaScript代码，不做修改
        // RSI计算函数
        function calculateRSI(data, period) {
            if (data.length < period + 1) {
                return Array(data.length).fill(null);
            }

            const rsi = Array(period).fill(null);
            let avgGain = 0;
            let avgLoss = 0;

            // 计算初始平均值
            for (let i = 1; i <= period; i++) {
                const change = data[i].close - data[i - 1].close;
                if (change > 0) {
                    avgGain += change;
                } else {
                    avgLoss += Math.abs(change);
                }
            }

            avgGain /= period;
            avgLoss /= period;

            // 计算第一个RSI值
            const rs = avgLoss === 0 ? 100 : avgGain / avgLoss;
            rsi.push(100 - (100 / (1 + rs)));

            // 计算后续RSI值
            for (let i = period + 1; i < data.length; i++) {
                const change = data[i].close - data[i - 1].close;
                let gain = 0;
                let loss = 0;

                if (change > 0) {
                    gain = change;
                    loss = 0;
                } else {
                    gain = 0;
                    loss = Math.abs(change);
                }

                // 平滑计算平均值
                avgGain = (avgGain * (period - 1) + gain) / period;
                avgLoss = (avgLoss * (period - 1) + loss) / period;

                const rs = avgLoss === 0 ? 100 : avgGain / avgLoss;
                rsi.push(100 - (100 / (1 + rs)));
            }

            return rsi;
        }

        // MACD计算函数
        function calculateMACD(data, shortPeriod = 12, longPeriod = 26, signalPeriod = 9) {
            if (data.length < longPeriod + signalPeriod) {
                return {
                    dif: Array(data.length).fill(null),
                    dea: Array(data.length).fill(null),
                    macd: Array(data.length).fill(null)
                };
            }

            // 计算短期EMA和长期EMA
            const shortEMA = calculateEMA(data, shortPeriod);
            const longEMA = calculateEMA(data, longPeriod);

            // 计算DIF
            const dif = shortEMA.map((val, i) => val !== null && longEMA[i] !== null ? val - longEMA[i] : null);

            // 计算DEA (DIF的signalPeriod日EMA)
            const dea = calculateEMA(dif.map((val, i) => ({ close: val || 0, time: data[i]?.time || 0 })), signalPeriod);

            // 计算MACD柱状图 (DIF-DEA)*2
            const macd = dif.map((val, i) => val !== null && dea[i] !== null ? (val - dea[i]) * 2 : null);

            return { dif, dea, macd };
        }

        // EMA计算函数 (MACD辅助函数)
        function calculateEMA(data, period) {
            const ema = Array(period - 1).fill(null);
            if (data.length < period) return ema;

            // 计算SMA作为初始值
            let sum = 0;
            for (let i = 0; i < period; i++) {
                sum += data[i].close;
            }
            ema.push(sum / period);

            // 计算后续EMA值
            const multiplier = 2 / (period + 1);
            for (let i = period; i < data.length; i++) {
                ema.push((data[i].close - ema[i - 1]) * multiplier + ema[i - 1]);
            }

            return ema;
        }

        // KDJ计算函数
        function calculateKDJ(data, period = 9, kPeriod = 3, dPeriod = 3) {
            if (data.length < period + dPeriod) {
                return {
                    k: Array(data.length).fill(null),
                    d: Array(data.length).fill(null),
                    j: Array(data.length).fill(null)
                };
            }

            const kValues = [];
            const dValues = [];
            const jValues = [];

            // 计算RSV值
            for (let i = 0; i < data.length; i++) {
                if (i < period - 1) {
                    kValues.push(null);
                    dValues.push(null);
                    jValues.push(null);
                    continue;
                }

                // 找出period日内的最高价和最低价
                let high = -Infinity;
                let low = Infinity;
                for (let j = i - period + 1; j <= i; j++) {
                    high = Math.max(high, data[j].high);
                    low = Math.min(low, data[j].low);
                }

                const close = data[i].close;
                const rsv = (close - low) / (high - low) * 100;

                // 计算K值 (RSV的kPeriod日平滑)
                let k = rsv;
                if (kValues[i - 1] !== null) {
                    k = (kValues[i - 1] * (kPeriod - 1) + rsv) / kPeriod;
                }
                kValues.push(k);

                // 计算D值 (K值的dPeriod日平滑)
                let d = k;
                if (dValues[i - 1] !== null) {
                    d = (dValues[i - 1] * (dPeriod - 1) + k) / dPeriod;
                }
                dValues.push(d);

                // 计算J值
                jValues.push(3 * k - 2 * d);
            }

            return { k: kValues, d: dValues, j: jValues };
        }

        // 布林带计算函数
        function calculateBollingerBands(data, period = 20, multiplier = 2) {
            if (data.length < period) {
                return {
                    upper: Array(data.length).fill(null),
                    middle: Array(data.length).fill(null),
                    lower: Array(data.length).fill(null),
                    bandwidth: Array(data.length).fill(null),
                    percentB: Array(data.length).fill(null)
                };
            }

            const middle = calculateMA(data, period);
            const upper = [];
            const lower = [];
            const bandwidth = [];
            const percentB = [];

            // 计算标准差
            for (let i = 0; i < data.length; i++) {
                if (i < period - 1) {
                    upper.push(null);
                    lower.push(null);
                    bandwidth.push(null);
                    percentB.push(null);
                    continue;
                }

                // 计算标准差
                let sum = 0;
                for (let j = i - period + 1; j <= i; j++) {
                    sum += Math.pow(data[j].close - middle[i], 2);
                }
                const stdDev = Math.sqrt(sum / period);

                // 计算上下轨
                upper.push(middle[i] + multiplier * stdDev);
                lower.push(middle[i] - multiplier * stdDev);

                // 计算带宽
                bandwidth.push(((upper[i] - lower[i]) / middle[i]) * 100);

                // 计算%B
                percentB.push((data[i].close - lower[i]) / (upper[i] - lower[i]) * 100);
            }

            return { upper, middle, lower, bandwidth, percentB };
        }

        // 支撑阻力位计算函数 (基于经典枢轴点)
        function calculatePivotPoints(data) {
            const pivots = {
                r3: Array(data.length).fill(null),
                r2: Array(data.length).fill(null),
                r1: Array(data.length).fill(null),
                s1: Array(data.length).fill(null),
                s2: Array(data.length).fill(null),
                s3: Array(data.length).fill(null),
                pp: Array(data.length).fill(null)
            };

            // 需要至少2天数据才能计算
            if (data.length < 2) return pivots;

            // 从第二天开始计算
            for (let i = 1; i < data.length; i++) {
                // 获取前一交易日的高、低、收
                const prevHigh = data[i - 1].high;
                const prevLow = data[i - 1].low;
                const prevClose = data[i - 1].close;

                // 计算枢轴点
                const pp = (prevHigh + prevLow + prevClose) / 3;

                // 标准支撑阻力位计算
                const r1 = 2 * pp - prevLow;
                const s1 = 2 * pp - prevHigh;
                const r2 = pp + (prevHigh - prevLow);
                const s2 = pp - (prevHigh - prevLow);
                const r3 = pp + 2 * (prevHigh - prevLow);
                const s3 = pp - 2 * (prevHigh - prevLow);

                // 填充当前值
                pivots.pp[i] = pp;
                pivots.r1[i] = r1;
                pivots.s1[i] = s1;
                pivots.r2[i] = r2;
                pivots.s2[i] = s2;
                pivots.r3[i] = r3;
                pivots.s3[i] = s3;
            }

            return pivots;
        }

        // 辅助函数 - 计算简单移动平均线
        function calculateMA(data, period) {
            const ma = [];
            for (let i = 0; i < data.length; i++) {
                if (i < period - 1) {
                    ma.push(null);
                    continue;
                }

                let sum = 0;
                for (let j = i - period + 1; j <= i; j++) {
                    sum += data[j].close;
                }
                ma.push(sum / period);
            }
            return ma;
        }

        // 辅助函数 - 获取趋势类名 
        function getTrendClass(current, previous) {
            if (current === null || previous === null) return '';
            return current > previous ? 'positive' : current < previous ? 'negative' : '';
        }

        // 辅助函数 - 获取RSI类名
        function getRSIClass(rsiValue) {
            if (!rsiValue) return '';
            if (rsiValue > 70) return 'negative'; // 超买 
            if (rsiValue < 30) return 'positive'; // 超卖
            return '';
        }

        // 辅助函数 - RSI级别描述
        function getRSILevel(rsiValue) {
            if (!rsiValue) return 'N/A';
            if (rsiValue > 80) return '极端超买';
            if (rsiValue > 70) return '超买';
            if (rsiValue < 20) return '极端超卖';
            if (rsiValue < 30) return '超卖';
            if (rsiValue > 60) return '强势';
            if (rsiValue < 40) return '弱势';
            return '中性';
        }

        // 数值格式化
        function formatValue(value) {
            return value === null ? 'N/A' : value.toFixed(2);
        }

        // 获取趋势颜色 
        function getTrendColor(current, previous) {
            if (current === null || previous === null) return '';
            if (current > previous) return 'positive';
            if (current < previous) return 'negative';
            return 'text-gray-400';
        }

        // 获取趋势箭头 
        function getTrendArrow(current, previous) {
            if (current === null || previous === null) return '';
            if (current > previous) return '↗';
            if (current < previous) return '↘';
            return '→';
        }

        // RSI颜色和状态 
        function getRSIColor(rsiValue) {
            if (!rsiValue) return '';
            if (rsiValue > 70) return 'negative'; // 超买
            if (rsiValue < 30) return 'positive'; // 超卖 
            if (rsiValue > 50) return 'positive-light'; // 强势区 
            return 'negative-light'; // 弱势区 
        }

        // 更新后的RSI水平描述函数（带趋势箭头） 
        function getRSILevelWithArrow(rsiValue, prevRsiValue = null) {
            if (!rsiValue) return 'N/A';
            
            // 获取趋势箭头（如果有前值）
            const arrow = prevRsiValue !== null ? getRSITrendArrow(rsiValue, prevRsiValue) : '';
            
            // RSI水平判断 
            let level;
            if (rsiValue > 70) level = '超买';
            else if (rsiValue < 30) level = '超卖';
            else if (rsiValue > 50) level = '强势';
            else level = '弱势';
            
            return `${level}${arrow}`;
        }

        // RSI趋势箭头判断 
        function getRSITrendArrow(current, previous) {
            if (current === null || previous === null) return '';
            if (current > previous) return ' ↗'; // 上升趋势 
            if (current < previous) return ' ↘'; // 下降趋势 
            return ' →'; // 持平 
        }

        // 布林带颜色判断函数
        function getBBColor(bandType, currentPrice, upper, lower) {
            if (currentPrice === null || upper === null || lower === null) return '';
            
            // 上轨颜色规则
            if (bandType === 'upper') {
                return currentPrice >= upper ? 'negative' : ''; // 价格触及上轨显示红色
            }
            // 下轨颜色规则 
            else if (bandType === 'lower') {
                return currentPrice <= lower ? 'positive' : ''; // 价格触及下轨显示绿色
            }
            return '';
        }

        // 增强RSI颜色判断
        function getRSIColorClass(rsiValue) {
            if (!rsiValue) return '';
            if (rsiValue > 80) return 'text-negative font-bold';    // 极端超买 
            if (rsiValue > 70) return 'text-negative';         // 超买
            if (rsiValue < 20) return 'text-positive font-bold';    // 极端超卖
            if (rsiValue < 30) return 'text-positive';         // 超卖
            if (rsiValue > 60) return 'text-positive-light';   // 强势区 
            if (rsiValue < 40) return 'text-negative-light';   // 弱势区
            return '';                                    // 中性区域无颜色
        }

        // 增强RSI级别描述
        function getRSILevelDescription(rsiValue) {
            if (!rsiValue) return 'N/A';
            if (rsiValue > 80) return '极端超买';
            if (rsiValue > 70) return '超买';
            if (rsiValue < 20) return '极端超卖';
            if (rsiValue < 30) return '超卖';
            if (rsiValue > 60) return '强势';
            if (rsiValue < 40) return '弱势';
            return '中性';
        }

        class Backtester {
            constructor() {
                this.historicalData  = {};
                this.backtestResults  = {};
            }

            // 获取对应周期的历史数据 
            async fetchHistoricalData(symbol, interval, limit = 500) {
                try {
                    const url = `https://bnapi.bnlex.top/fapi/fapi/v1/klines?symbol=${symbol}&interval=${interval}&limit=${limit}`; 
                    const response = await fetch(url);
                    const data = await response.json(); 
                    
                    return data.map(item  => ({
                        time: Math.floor(item[0]  / 1000),
                        open: parseFloat(item[1]),
                        high: parseFloat(item[2]),
                        low: parseFloat(item[3]),
                        close: parseFloat(item[4]),
                        volume: parseFloat(item[5]),
                        closeTime: item[6]
                    }));
                } catch (error) {
                    console.error(` 获取${symbol}历史数据失败:`, error);
                    return null;
                }
            }

            // 根据当前信号回测历史数据
            async backtestStrategy(symbol, currentInterval) {
                // 确定获取数据的周期
                let fetchInterval;
                switch(currentInterval) {
                    case '10m': fetchInterval = '5m'; break;
                    case '30m': fetchInterval = '15m'; break;
                    default: fetchInterval = currentInterval;
                }
                
                // 获取历史数据 
                const rawData = await this.fetchHistoricalData(symbol,  fetchInterval);
                if (!rawData || rawData.length  < 100) return null;
                
                // 如果需要转换周期（如10分钟用5分钟数据，30分钟用15分钟数据）
                let historicalData;
                if (currentInterval === '10m' || currentInterval === '30m') {
                    // 10分钟周期使用5分钟数据，转换因子为2；30分钟周期使用15分钟数据，转换因子为2
                    historicalData = this.convertToHigherTimeframe(rawData, 2);
                } else {
                    historicalData = rawData;
                }
                    
                // 确保数据长度足够
                if (historicalData.length  < 100) return null;
                
                // 计算当前信号 
                const currentSignals = this.calculateSignals(historicalData); 
                if (!currentSignals.prediction)  return null;
                
                // 回测逻辑 
                const backtestResults = this.runBacktest(historicalData,  currentSignals);
                
                // 存储结果 
                this.backtestResults[symbol]  = backtestResults;
                return backtestResults;
            }

            // 将低周期数据转换为高周期数据
            convertToHigherTimeframe(data, factor) {
                const converted = [];
                for (let i = 0; i < data.length  - factor + 1; i += factor) {
                    const chunk = data.slice(i,  i + factor);
                    const newCandle = {
                        time: chunk[0].time,
                        open: chunk[0].open,
                        high: Math.max(...chunk.map(c  => c.high)), 
                        low: Math.min(...chunk.map(c  => c.low)), 
                        close: chunk[chunk.length - 1].close,
                        volume: chunk.reduce((sum,  c) => sum + c.volume,  0),
                        closeTime: chunk[chunk.length - 1].closeTime
                    };
                    converted.push(newCandle); 
                }
                return converted;
            }

            // 计算信号（与CryptoAnalyzer中的方法类似）
            calculateSignals(data) {
                const lastIndex = data.length  - 1;
                
                // 计算各种技术指标
                const ma5 = calculateMA(data, 5);
                const ma10 = calculateMA(data, 10);
                const ma20 = calculateMA(data, 20);
                const rsi = calculateRSI(data, 14);
                const macd = calculateMACD(data);
                const kdj = calculateKDJ(data);
                
                // 计算趋势 
                const ma5Trend = this.getTrend(ma5,  lastIndex);
                const ma10Trend = this.getTrend(ma10,  lastIndex);
                const ma20Trend = this.getTrend(ma20,  lastIndex);
                const rsiTrend = this.getTrend(rsi,  lastIndex);
                const macdTrend = this.getMACDTrend(macd,  lastIndex);
                const kdjCross = this.getKDJCross(kdj,  lastIndex);
                
                // 计算成交量
                const volumes = data.map(d  => d.volume); 
                const volumeMa20 = calculateMA(data.map(d  => ({close: d.volume})),  20)[lastIndex];
                const volumeTrend = this.getTrend(volumes,  lastIndex);
                
                // 生成预测 
                const prediction = this.generatePrediction({ 
                    ma5Trend, ma10Trend, ma20Trend,
                    rsi: rsi[lastIndex], rsiTrend,
                    macdDiff: macd.dif[lastIndex]  - macd.dea[lastIndex], 
                    macdTrend,
                    kdjCross,
                    volume: {
                        current: volumes[lastIndex],
                        ma20: volumeMa20,
                        trend: volumeTrend
                    }
                });
                
                return {
                    indicators: {
                        ma5: ma5[lastIndex],
                        ma10: ma10[lastIndex],
                        ma20: ma20[lastIndex],
                        rsi: rsi[lastIndex],
                        macd: macd,
                        kdj: kdj
                    },
                    prediction 
                };
            }

            // 运行回测 
            runBacktest(data, currentSignals, testPeriods = 200) { // 增加默认参数，扩大测试周期
                const maxPeriods = Math.min(testPeriods, data.length - 100); // 确保有足够数据计算指标
                const signals = [];
                let correctPredictions = 0;
                let totalPredictions = 0;
                
                // 从数据开始部分开始测试，留出足够的数据计算指标
                for (let i = 100; i < data.length  - 1 && totalPredictions < maxPeriods; i++) {
                    const testData = data.slice(0,  i + 1);
                    const testSignals = this.calculateSignals(testData); 
                    
                    // 只测试与当前信号相似的信号
                    if (this.isSimilarSignal(testSignals.prediction,  currentSignals.prediction))  {
                        totalPredictions++;
                        
                        // 判断预测是否正确
                        const actualMovement = data[i + 1].close > data[i].close ? 'up' : 'down';
                        if (testSignals.prediction.direction  === actualMovement) {
                            correctPredictions++;
                        }
                        
                        signals.push({ 
                            time: data[i].time,
                            prediction: testSignals.prediction.direction, 
                            actual: actualMovement,
                            correct: testSignals.prediction.direction  === actualMovement
                        });
                    }
                    
                    if (totalPredictions >= testPeriods) break;
                }
                
                const winRate = totalPredictions > 0 ? 
                    Math.round((correctPredictions  / totalPredictions) * 100) : 0;
                    
                return {
                    winRate,
                    totalTests: totalPredictions,
                    correctPredictions,
                    signals 
                };
            }

            // 判断两个信号是否相似
            isSimilarSignal(signal1, signal2) {
                // 方向相同
                if (signal1.direction  !== signal2.direction)  return false;
                
                // RSI处于相似区域
                const rsi1 = signal1.rsi; 
                const rsi2 = signal2.rsi; 
                if ((rsi1 > 70 && rsi2 < 70) || (rsi1 < 30 && rsi2 > 30)) return false;
                
                // MACD趋势相似 
                if (signal1.macdTrend  !== signal2.macdTrend)  return false;
                
                // KDJ交叉状态相似
                if (signal1.kdjCross && signal2.kdjCross) {
                    // 如果两个信号都有KDJ交叉状态，则需要比较
                    if (!['goldenCross', 'deathCross'].includes(signal1.kdjCross) || 
                        !['goldenCross', 'deathCross'].includes(signal2.kdjCross)) {
                        // 非主要交叉类型，可以接受
                    } else if (signal1.kdjCross !== signal2.kdjCross) {
                        return false;
                    }
                }
                
                // 成交量趋势相似
                if (signal1.volume && signal2.volume) {
                    if (signal1.volume.trend !== signal2.volume.trend) {
                        return false;
                    }
                }
                
                return true;
            }

            // 以下是从CryptoAnalyzer复制的辅助方法 
            getTrend(values, index) {
                if (index < 2 || !values[index] || !values[index-1]) return 'neutral';
                return values[index] > values[index-1] ? 'up' : 'down';
            }

            getMACDTrend(macd, index) {
                if (index < 2 || !macd.dif[index]  || !macd.dea[index])  return 'neutral';
                
                const dif = macd.dif[index],  dea = macd.dea[index]; 
                const prevDif = macd.dif[index-1],  prevDea = macd.dea[index-1]; 
                
                if (dif > dea && dif > prevDif && dea > prevDea) return 'strongUp';
                if (dif < dea && dif < prevDif && dea < prevDea) return 'strongDown';
                if (dif > dea && prevDif < prevDea) return 'crossUp';
                if (dif < dea && prevDif > prevDea) return 'crossDown';
                
                return 'neutral';
            }

            getKDJCross(kdj, index) {
                if (index < 2 || !kdj.k[index] || !kdj.d[index]) return 'neutral';
                
                const k = kdj.k[index], d = kdj.d[index];
                const prevK = kdj.k[index-1], prevD = kdj.d[index-1];
                
                if (k > d && prevK < prevD) return 'goldenCross';
                if (k < d && prevK > prevD) return 'deathCross';
                if (k > d) return 'above';
                if (k < d) return 'below';
                return 'neutral';
            }

            generatePrediction(signals) {
                // 1. 趋势信号 
                const trendSignal = this.detectTrend(signals); 
                
                // 2. 反转信号 
                const reversalSignal = this.detectReversal(signals); 
                
                // 3. 综合决策 
                return this.combineSignals(trendSignal,  reversalSignal, signals);
            }

            detectTrend(signals) {
                let confidence = 0.5; // 基础置信度
                
                // 计算各种条件
                const maUp = signals.ma5Trend  === 'up' && signals.ma10Trend  === 'up';
                const maDown = signals.ma5Trend  === 'down' && signals.ma10Trend  === 'down';
                
                const macdUp = ['crossUp', 'strongUp'].includes(signals.macdTrend); 
                const macdDown = ['crossDown', 'strongDown'].includes(signals.macdTrend); 
                
                const kdjUp = signals.kdjCross  === 'goldenCross';
                const kdjDown = signals.kdjCross  === 'deathCross';
                
                // 计算趋势强度分数
                let upScore = 0;
                let downScore = 0;
                
                if (maUp) upScore += 0.3;
                if (macdUp) upScore += 0.3;
                if (kdjUp) upScore += 0.3;
                if (signals.rsi  < 30) upScore += 0.1; // 超卖区域增加看涨分数
                
                if (maDown) downScore += 0.3;
                if (macdDown) downScore += 0.3;
                if (kdjDown) downScore += 0.3;
                if (signals.rsi  > 70) downScore += 0.1; // 超买区域增加看跌分数
                
                // 确定方向和置信度
                if (upScore > downScore) {
                    confidence = 0.5 + upScore; // 基础置信度加上向上分数
                    confidence = Math.min(confidence, 0.95); // 最大置信度限制为0.95
                    return { direction: 'up', confidence, type: 'trend', rsi: signals.rsi, macdTrend: signals.macdTrend };
                } else if (downScore > upScore) {
                    confidence = 0.5 + downScore; // 基础置信度加上向下分数
                    confidence = Math.min(confidence, 0.95); // 最大置信度限制为0.95
                    return { direction: 'down', confidence, type: 'trend', rsi: signals.rsi, macdTrend: signals.macdTrend };
                }
                
                return { direction: 'neutral', confidence: 0.5, type: 'trend', rsi: signals.rsi, macdTrend: signals.macdTrend };
            }

            detectReversal(signals) {
                const extremeRsi = signals.rsi  > 70 || signals.rsi  < 30;
                const volumeSpike = signals.volume.current  > signals.volume.ma20  * 1.5;
                
                // 顶部反转 
                if (signals.rsi  > 70 && signals.rsiTrend  === 'down' &&
                    signals.macdTrend  === 'crossDown' && volumeSpike) {
                    return { direction: 'down', confidence: 0.65, type: 'reversal', rsi: signals.rsi, macdTrend: signals.macdTrend };
                }
                
                // 底部反转
                if (signals.rsi  < 30 && signals.rsiTrend  === 'up' &&
                    signals.macdTrend  === 'crossUp' && volumeSpike) {
                    return { direction: 'up', confidence: 0.65, type: 'reversal', rsi: signals.rsi, macdTrend: signals.macdTrend };
                }
                
                return null;
            }

            combineSignals(trend, reversal, signals) {
                // 趋势信号强时优先 
                if (trend.confidence  >= 0.7) return trend;
                
                // 反转信号需满足成交量确认 
                if (reversal && this.volumeConfirms(reversal,  signals)) {
                    return reversal;
                }
                
                return trend;
            }

            volumeConfirms(signal, signals) {
                const volumeTrendMatch = signal.direction  === 'up' 
                    ? signals.volume.trend  === 'up'
                    : signals.volume.trend  === 'down';
                    
                return volumeTrendMatch && signals.volume.current  > signals.volume.ma20; 
            }
        }

        class CryptoAnalyzer {
            constructor() {
                this.symbols  = ['BTCUSDT', 'ETHUSDT'];
                this.historicalData  = {};
                this.volumeData  = {};
                this.currentSignals  = {};
                this.backtester  = new Backtester();
                
                this.symbols.forEach(symbol  => {
                    this.historicalData[symbol]  = {};
                    this.volumeData[symbol]  = {};
                    this.currentSignals[symbol]  = {};
                });
            }

            // 核心方法
            async startAnalysis() {
                const selectedInterval = document.getElementById('analysis-period').value; 
                await this.fetchDataForAllSymbols(); 
                
                for (const symbol of this.symbols)  {
                    this.analyzeCurrentData(symbol,  selectedInterval);

                    // 运行回测 
                    const backtestResult = await this.backtester.backtestStrategy(symbol,  selectedInterval);
                    if (backtestResult) {
                        this.currentSignals[symbol][selectedInterval].backtest  = backtestResult;
                    }
                }

                const result = {
                    currentSignals: {
                        BTCUSDT: { [selectedInterval]: this.currentSignals.BTCUSDT[selectedInterval]  },
                        ETHUSDT: { [selectedInterval]: this.currentSignals.ETHUSDT[selectedInterval]  }
                    }
                };
                
                updateAnalysisResults(result);
                return result;
            }

            async fetchDataForAllSymbols() {
                const fetchPromises = [];
                const selectedInterval = document.getElementById('analysis-period').value; 
                
                for (const symbol of this.symbols)  {
                    const fetchInterval = selectedInterval === '10m' ? '5m' : selectedInterval;
                    fetchPromises.push(this.fetchAndProcessData(symbol,  fetchInterval, selectedInterval));
                }
                
                await Promise.all(fetchPromises); 
            }

            async fetchAndProcessData(symbol, fetchInterval, displayInterval) {
                try {
                    const limit = fetchInterval === '5m' ? 600 : 300;
                    const url = `https://bnapi.bnlex.top/fapi/fapi/v1/klines?symbol=${symbol}&interval=${fetchInterval}&limit=${limit}`; 
                    const response = await fetch(url);
                    
                    if (!response.ok)  throw new Error(`HTTP ${response.status}`); 
                    
                    const klineData = await response.json(); 
                    const formattedData = this.formatKlineData(klineData,  displayInterval);
                    
                    this.storeData(symbol,  displayInterval, formattedData);
                    this.analyzeCurrentData(symbol,  displayInterval);
                    return true;
                } catch (error) {
                    console.error(` 获取${symbol}数据失败:`, error);
                    return false;
                }
            }

            // 数据处理方法
            formatKlineData(klineData, displayInterval) {
                const formatted = klineData.map(item  => ({
                    time: Math.floor(item[0]  / 1000),
                    open: parseFloat(item[1]),
                    high: parseFloat(item[2]),
                    low: parseFloat(item[3]),
                    close: parseFloat(item[4]),
                    volume: parseFloat(item[5]),
                    closeTime: item[6]
                }));

                return displayInterval === '10m' ? this.convert5mTo10m(formatted)  : formatted;
            }

            getSupportResistance(data, periods) {
                const lastIndex = data.length  - 1;
                
                // 当前价格
                const currentPrice = data[lastIndex].close;
                
                // 动态均线作为基础支撑阻力
                const maShort = calculateMA(data, periods.maShort)[lastIndex]; 
                const maMedium = calculateMA(data, periods.maMedium)[lastIndex]; 
                const maLong = calculateMA(data, periods.maLong)[lastIndex]; 
                
                // 布林带计算（使用动态周期）
                const bb = calculateBollingerBands(data, periods.maMedium);  // 使用中期均线周期
                
                return {
                    // 基础支撑阻力
                    support1: maMedium * 0.995,  // 中期均线略微下移
                    resistance1: maMedium * 1.005, // 中期均线略微上移
                    
                    // 动态支撑阻力（基于布林带）
                    support2: bb.lower[lastIndex], 
                    resistance2: bb.upper[lastIndex], 
                    
                    // 心理整数位支撑阻力
                    support3: Math.floor(currentPrice  / 10) * 10,
                    resistance3: Math.ceil(currentPrice  / 10) * 10,
                    
                    // 近期高低点
                    support4: this.getRecentLow(data,  24), // 最近24根K线低点
                    resistance4: this.getRecentHigh(data,  24) // 最近24根K线高点
                };
            }

            // 辅助方法：获取近期低点
            getRecentLow(data, periods) {
                return Math.min(...data.slice(-periods).map(d  => d.low)); 
            }

            // 辅助方法：获取近期高点
            getRecentHigh(data, periods) {
                return Math.max(...data.slice(-periods).map(d  => d.high)); 
            }

            convert5mTo10m(data) {
                const merged = [];
                for (let i = 0; i < data.length  - 1; i += 2) {
                    const candle1 = data[i];
                    const candle2 = data[i + 1];
                    merged.push({ 
                        time: candle1.time, 
                        open: candle1.open, 
                        high: Math.max(candle1.high,  candle2.high), 
                        low: Math.min(candle1.low,  candle2.low), 
                        close: candle2.close, 
                        volume: candle1.volume  + candle2.volume, 
                        closeTime: candle2.closeTime  
                    });
                }
                return merged.length  > 0 ? merged : data;
            }

            storeData(symbol, interval, data) {
                this.historicalData[symbol][interval]  = data;
                this.volumeData[symbol][interval]  = data.map(d  => d.volume); 
            }

            // 信号分析方法
            analyzeCurrentData(symbol, interval) {
                const data = this.historicalData[symbol]?.[interval]; 
                if (!data || data.length  < 50) return;

                const lastIndex = data.length  - 1;
                const signals = this.calculateAllIndicators(data,  interval);
                
                // 添加支撑阻力位计算
                signals.supports  = this.getSupportResistance(data,  signals.periods); 
                
                // 添加成交量分析
                signals.volume  = {
                    current: data[lastIndex].volume,
                    ma20: calculateMA(data.map(d  => ({close: d.volume})),  20)[lastIndex],
                    trend: this.getTrend(data.map(d  => d.volume),  lastIndex)
                };

                // 存储结果
                this.currentSignals[symbol][interval]  = {
                    ...signals,
                    prediction: this.generatePrediction(signals) 
                };
            }

            generatePrediction(signals) {
                // 1. 趋势信号 
                const trendSignal = this.detectTrend(signals); 
                
                // 2. 反转信号 
                const reversalSignal = this.detectReversal(signals); 
                
                // 3. 综合决策 
                return this.combineSignals(trendSignal,  reversalSignal, signals);
            }

            // 策略逻辑
            detectTrend(signals) {
                const maUp = signals.maShortTrend  === 'up' && signals.maMediumTrend  === 'up';
                const maDown = signals.maShortTrend  === 'down' && signals.maMediumTrend  === 'down';
                
                const macdUp = ['crossUp', 'strongUp'].includes(signals.macdTrend); 
                const macdDown = ['crossDown', 'strongDown'].includes(signals.macdTrend); 
                
                const kdjUp = signals.kdjCross  === 'goldenCross';
                const kdjDown = signals.kdjCross  === 'deathCross';
                
                const upConditions = (maUp || macdUp) && (kdjUp || signals.rsi  < 70);
                const downConditions = (maDown || macdDown) && (kdjDown || signals.rsi  > 30);
                
                if (upConditions) {
                    return { direction: 'up', confidence: 0.7, type: 'trend', rsi: signals.rsi, macdTrend: signals.macdTrend };
                } else if (downConditions) {
                    return { direction: 'down', confidence: 0.7, type: 'trend', rsi: signals.rsi, macdTrend: signals.macdTrend };
                }
                return { direction: 'neutral', confidence: 0.5, type: 'trend', rsi: signals.rsi, macdTrend: signals.macdTrend };
            }

            // 带interval参数的calculateAllIndicators函数
            calculateAllIndicators(data, interval) {
                const lastIndex = data.length  - 1;
                
                const getPeriods = () => {
                    switch(interval) {
                        case '10m': return { maShort: 6, maMedium: 12, maLong: 24 };
                        case '30m': return { maShort: 8, maMedium: 16, maLong: 32 };
                        case '1h': return { maShort: 5, maMedium: 10, maLong: 20 };
                        default: return { maShort: 5, maMedium: 10, maLong: 20 };
                    }
                };
                
                const periods = getPeriods();
                
                return {
                    price: data[lastIndex].close,
                    maShort: calculateMA(data, periods.maShort)[lastIndex], 
                    maMedium: calculateMA(data, periods.maMedium)[lastIndex], 
                    maLong: calculateMA(data, periods.maLong)[lastIndex], 
                    maShortTrend: this.getTrend(calculateMA(data,  periods.maShort),  lastIndex),
                    maMediumTrend: this.getTrend(calculateMA(data,  periods.maMedium),  lastIndex),
                    maLongTrend: this.getTrend(calculateMA(data,  periods.maLong),  lastIndex),
                    rsi: calculateRSI(data, 14)[lastIndex],
                    rsiTrend: this.getTrend(calculateRSI(data,  14), lastIndex),
                    macdDiff: calculateMACD(data).dif[lastIndex] - calculateMACD(data).dea[lastIndex],
                    macdTrend: this.getMACDTrend(calculateMACD(data),  lastIndex),
                    kdjCross: this.getKDJCross(calculateKDJ(data),  lastIndex),
                    periods // 将周期配置也返回 
                };
            }

            detectReversal(signals) {
                const extremeRsi = signals.rsi  > 70 || signals.rsi  < 30;
                const volumeSpike = signals.volume.current  > signals.volume.ma20  * 1.5;
                
                // 顶部反转 
                if (signals.rsi  > 70 && signals.rsiTrend  === 'down' &&
                    signals.macdTrend  === 'crossDown' && volumeSpike) {
                    return { direction: 'down', confidence: 0.65, type: 'reversal', rsi: signals.rsi, macdTrend: signals.macdTrend };
                }
                
                // 底部反转
                if (signals.rsi  < 30 && signals.rsiTrend  === 'up' &&
                    signals.macdTrend  === 'crossUp' && volumeSpike) {
                    return { direction: 'up', confidence: 0.65, type: 'reversal', rsi: signals.rsi, macdTrend: signals.macdTrend };
                }
                
                return null;
            }

            combineSignals(trend, reversal, signals) {
                // 趋势信号强时优先 
                if (trend.confidence  >= 0.7) return trend;
                
                // 反转信号需满足成交量确认 
                if (reversal && this.volumeConfirms(reversal,  signals)) {
                    return reversal;
                }
                
                return trend;
            }

            volumeConfirms(signal, signals) {
                const volumeTrendMatch = signal.direction  === 'up' 
                    ? signals.volume.trend  === 'up'
                    : signals.volume.trend  === 'down';
                    
                return volumeTrendMatch && signals.volume.current  > signals.volume.ma20; 
            }

            // 辅助方法
            getTrend(values, index) {
                if (index < 2 || !values[index] || !values[index-1]) return 'neutral';
                return values[index] > values[index-1] ? 'up' : 'down';
            }

            getMACDTrend(macd, index) {
                if (index < 2 || !macd.dif[index]  || !macd.dea[index])  return 'neutral';
                
                const dif = macd.dif[index],  dea = macd.dea[index]; 
                const prevDif = macd.dif[index-1],  prevDea = macd.dea[index-1]; 
                
                if (dif > dea && dif > prevDif && dea > prevDea) return 'strongUp';
                if (dif < dea && dif < prevDif && dea < prevDea) return 'strongDown';
                if (dif > dea && prevDif < prevDea) return 'crossUp';
                if (dif < dea && prevDif > prevDea) return 'crossDown';
                
                return 'neutral';
            }

            getKDJCross(kdj, index) {
                if (index < 2 || !kdj.k[index] || !kdj.d[index]) return 'neutral';
                
                const k = kdj.k[index], d = kdj.d[index];
                const prevK = kdj.k[index-1], prevD = kdj.d[index-1];
                
                if (k > d && prevK < prevD) return 'goldenCross';
                if (k < d && prevK > prevD) return 'deathCross';
                if (k > d) return 'above';
                if (k < d) return 'below';
                return 'neutral';
            }
        }

        // 页面交互逻辑
        document.addEventListener('DOMContentLoaded', () => {
            const analyzer = new CryptoAnalyzer();
            const startButton = document.getElementById('start-analysis');
            const loadingIndicator = document.getElementById('loading-indicator');
            const analysisStatus = document.getElementById('analysis-status');
            const lastUpdateElement = document.getElementById('last-update');
            
            // 开始分析按钮点击事件
            startButton.addEventListener('click', async () => {
                startButton.disabled = true;
                loadingIndicator.classList.remove('hidden');
                analysisStatus.classList.add('hidden');
                
                try {
                    await analyzer.startAnalysis();
                    
                    // 更新最后更新时间
                    const now = new Date();
                    lastUpdateElement.textContent = `最后更新: ${now.toLocaleString()}`;
                    
                    analysisStatus.textContent = '分析完成';
                    analysisStatus.classList.remove('hidden');
                    analysisStatus.classList.add('text-green-400');
                } catch (error) {
                    console.error('分析过程出错:', error);
                    analysisStatus.textContent = '分析失败，请重试';
                    analysisStatus.classList.remove('hidden');
                    analysisStatus.classList.add('text-red-400');
                } finally {
                    loadingIndicator.classList.add('hidden');
                    startButton.disabled = false;
                }
            });
        });

        // 更新分析结果到页面
        function updateAnalysisResults(results) {
            const resultsContainer = document.getElementById('analysis-results');
            resultsContainer.innerHTML = '';
            
            const interval = Object.keys(results.currentSignals.BTCUSDT)[0];
            
            // 处理每个加密货币的结果
            Object.keys(results.currentSignals).forEach(symbol => {
                const signalData = results.currentSignals[symbol][interval];
                const prediction = signalData.prediction;
                
                // 准备卡片数据
                const trendColor = prediction.direction === 'up' ? 'text-positive' : prediction.direction === 'down' ? 'text-negative' : 'text-gray-400';
                const trendArrow = prediction.direction === 'up' ? '↗' : prediction.direction === 'down' ? '↘' : '→';
                const direction = prediction.direction;
                const confidence = Math.round(prediction.confidence * 100);
                
                const backtest = signalData.backtest || { winRate: 0, totalTests: 0 };
                const backtestWinRate = backtest.winRate;
                const backtestInfo = backtest.totalTests > 0 ? 
                    `<div class="text-xs text-gray-500">基于${backtest.totalTests}次历史数据回测</div>` : 
                    '<div class="text-xs text-gray-500">回测数据不足</div>';
                
                const rsiValue = signalData.rsi ? signalData.rsi.toFixed(2) : 'N/A';
                const rsiLevel = getRSILevelDescription(signalData.rsi);
                
                // 生成指标依据
                const indicatorReasons = [];
                if (signalData.maShortTrend === 'up' && signalData.maMediumTrend === 'up') {
                    indicatorReasons.push('短期和中期均线呈上升趋势');
                } else if (signalData.maShortTrend === 'down' && signalData.maMediumTrend === 'down') {
                    indicatorReasons.push('短期和中期均线呈下降趋势');
                }
                
                if (['crossUp', 'strongUp'].includes(signalData.macdTrend)) {
                    indicatorReasons.push('MACD指标呈上升趋势');
                } else if (['crossDown', 'strongDown'].includes(signalData.macdTrend)) {
                    indicatorReasons.push('MACD指标呈下降趋势');
                }
                
                if (signalData.kdjCross === 'goldenCross') {
                    indicatorReasons.push('KDJ指标出现金叉');
                } else if (signalData.kdjCross === 'deathCross') {
                    indicatorReasons.push('KDJ指标出现死叉');
                }
                
                if (signalData.rsi < 30) {
                    indicatorReasons.push('RSI指标处于超卖区域');
                } else if (signalData.rsi > 70) {
                    indicatorReasons.push('RSI指标处于超买区域');
                }
                
                // 生成操作建议
                let recommendation = '观望';
                if (prediction.direction === 'up' && prediction.confidence >= 0.65) {
                    recommendation = '买入';
                } else if (prediction.direction === 'down' && prediction.confidence >= 0.65) {
                    recommendation = '卖出';
                }
                
                // 创建卡片元素
                const card = document.createElement('div');
                card.className = 'bg-dark-light rounded-lg shadow-md overflow-hidden card-hover';
                
                // 使用指定的卡片HTML结构
                card.innerHTML = `
                    <div class="p-4 h-full flex flex-col">
                        <!-- 标题区 -->
                        <div class="flex justify-between items-center mb-3">
                            <h2 class="text-lg font-semibold">${symbol} 行情分析</h2>
                            <span class="text-xs bg-gray-700 px-2 py-1 rounded">${interval}</span>
                        </div>
                        
                        <!-- 核心指标区 -->
                        <div class="space-y-2 flex-1">
                            <!-- 趋势行 -->
                            <div class="flex justify-between">
                                <span class="text-gray-300">趋势判断</span>
                                <span class="${trendColor} font-medium">
                                    ${trendArrow} ${direction === 'up' ? '看涨' : '看跌'} 
                                    <span class="text-xs">(${confidence}%)</span>
                                </span>
                            </div>
                            
                            <div class="flex justify-between">
                                <span class="text-gray-300">回测胜率</span>
                                <span class="${backtestWinRate > 60 ? 'text-green-400' : backtestWinRate < 40 ? 'text-red-400' : 'text-yellow-400'}">
                                    ${backtestWinRate}%
                                </span>
                            </div>
                            ${backtestInfo}
                            
                            <!-- RSI行 -->
                            <div class="flex justify-between">
                                <span class="text-gray-300">RSI指数</span>
                                <span class="${getRSIColorClass(signalData.rsi)}">   
                                    ${rsiValue} <span class="text-xs">(${rsiLevel})</span>
                                </span>
                            </div>
                            
                            <!-- 价格行 -->
                            <div class="flex justify-between">
                                <span class="text-gray-300">当前价格</span>
                                <span class="font-mono">$${signalData.price.toFixed(2)}</span>   
                            </div>
                            
                            <!-- 指标依据 -->
                            <div class="bg-gray-800 p-2 rounded text-xs mt-2">
                                <div class="text-gray-400 mb-1">指标依据:</div>
                                <ul class="list-disc list-inside space-y-1">
                                    ${indicatorReasons.map(reason  => `<li>${reason}</li>`).join('')}
                                </ul>
                            </div>
                            
                            <!-- 建议区 -->
                            <div class="mt-4 pt-3 border-t border-gray-700">
                                <div class="flex justify-between items-center">
                                    <span class="text-gray-300">操作建议</span>
                                    <span class="${getRecommendationColor(recommendation)} font-medium">
                                        ${recommendation}
                                    </span>
                                </div>
                            </div>
                        </div>
                        
                        <!-- 支撑/阻力位 - 固定在底部 -->
                        <div class="mt-auto pt-4">
                            <div class="grid grid-cols-2 gap-4">
                                <div class="bg-gray-700 p-2 rounded">
                                    <div class="text-xs text-gray-400">主要支撑位</div>
                                    <div class="text-green-400 font-mono">${signalData.supports.support1.toFixed(2)}</div>  
                                    <div class="text-xs text-gray-500 mt-1">近期低点: ${signalData.supports.support4.toFixed(2)}</div>  
                                </div>
                                <div class="bg-gray-700 p-2 rounded">
                                    <div class="text-xs text-gray-400">主要阻力位</div>
                                    <div class="text-red-400 font-mono">${signalData.supports.resistance1.toFixed(2)}</div>  
                                    <div class="text-xs text-gray-500 mt-1">近期高点: ${signalData.supports.resistance4.toFixed(2)}</div>  
                                </div>
                            </div>
                        </div>
                    </div>`;
                
                resultsContainer.appendChild(card);
            });
        }

        // 获取建议颜色
        function getRecommendationColor(recommendation) {
            switch(recommendation) {
                case '买入': return 'text-green-400';
                case '卖出': return 'text-red-400';
                default: return 'text-yellow-400';
            }
        }
    </script>
</body>
</html>